/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author apu
 */
import java.io.*;
import java.util.*;

public class Game extends Thread{
	private boolean isActive, isRunning;
	private String myName,myPass;
	private int[][] board;
	private char symbol;
	int nMoves=0;

	//our own variables
	Vector<ArrayList<Move>> vTopToBottom = new Vector<ArrayList<Move>>();
	Vector<ArrayList<Move>> vLeftToRight = new Vector<ArrayList<Move>>();
	Vector<ArrayList<Move>> vDiagonalLeftToRight = new Vector<ArrayList<Move>>();
	Vector<ArrayList<Move>> vDiagonalRightToLeft = new Vector<ArrayList<Move>>();

	Vector<ArrayList<Move>> vSingle = new Vector<ArrayList<Move>>();
	Vector<ArrayList<Move>> vDouble = new Vector<ArrayList<Move>>();
	Vector<ArrayList<Move>> vTriple = new Vector<ArrayList<Move>>();
	Vector<ArrayList<Move>> vQuad = new Vector<ArrayList<Move>>();


	// The following event is called when the application is first launched...
	// You can use this you give yourself a name to connect to the server...
	public void App_Startup(){
		// You can also do this by using user input (i.e. a login prompt)
		// Only valid characters are a-z, 0-9 and _ (underscore)

		myName="UCIT";
		myPass="Cra55ckz";
	}
	// The following event is called when the server asks for player preference
	// That is, if you have any player that you would prefer to compete against
	// Choosing a pref increases your chance of encountering those player(s)
	// but it does not guarantee a match with those player. 
	public ArrayList<String> preferenceInit(ArrayList<String> onlinePlayers){
		ArrayList<String> pref=new ArrayList<String>();
		pref.clear();
		// Look at onlinePlayers and decide if you have any preferences
		// you dont even have to look at onlineplayers. if you have preference
		// for a specific handle (username) then list it anyways. if the player
		// is online then server will use your preference.

		// Since I have no preference, I am sending back an empty array list...

		return pref;
	}


	// This procedure is called every time a new game is to be initiated...
	public boolean Initialize_New_Game(String opName, int opID){
		// Setup states and data structures to begin a new game...

		board=new int[Move.MAXROW][Move.MAXCOL];
		for (int i=0;i<Move.MAXROW;i++) 
			for (int j=0;j<Move.MAXCOL;j++) board[i][j]=0;

		System.out.println("Staring a new game with"
				+" opponent "+opName+" [Team "+opID+"]");
		// Return true if you accept this opponent, otherwise return false
		// and the game will be rejected. The server will try to find 
		// another opponent for you.

		// YOU MUST RESPOND WITHIN THREE SECONDS

		return true;
	}

	// The following event occurs when you accept a game but 
	// your target opponent declines to play with you.
	public void Game_Declined(){
		// Not an important event
		// use it if you have allocated memory/data structures in the 
		// Initialize_New_Game event and free those structures.
	}

	// When you and the opponent accept the game the server
	// initiates a new game session (gameID) and sends you
	// your symbol x or o!... You dont need to use the following
	// event, but if you wanna keep a log of the games you played,
	// the following procedure could be useful...
	public void Receive_New_Game_ID(int gameID, char symbol){
		System.out.println("Starting Game# "+gameID+
				" assuming symbol " + symbol);      

	}

	// Opponent chose a move... Now it's your turn!
	// Move will be null when you're the first player to pick a move.
	public Move Update_Game(Move opponent){
		System.out.println("==== New move ====");
		
		
		if (opponent!=null)
		{
			board[opponent.Row()][opponent.Col()]=2;
			System.out.println("Opponents move was: " +opponent.Row() + opponent.Col());
		}
		if (opponent == null)
		{
			nMoves++;

			return new Move(3,3);
		}
		// find sequences of enemy tokens
		checkLeftRight();
		checkUpDown();
		checkDiagonalLeftRight();
		checkDiagonalRightLeft();


		//sort vector sequences
		grabSingles();
		grabDoubles();
		grabTriples();
		grabQuads();

		Move finalMove = null;

		while(finalMove == null)
		{

			//start trying the longest sequences
			if(!vQuad.isEmpty())
			{
				ArrayList<Move> pick = vQuad.firstElement();
				vQuad.remove(0);

				finalMove = pickMove(pick, checkType(pick));
			}
			else if(!vTriple.isEmpty())
			{
				ArrayList<Move> pick = vTriple.firstElement();
				vTriple.remove(0);

				finalMove = pickMove(pick, checkType(pick));

			}
			else if(!vDouble.isEmpty())
			{
				ArrayList<Move> pick = vDouble.firstElement();
				vDouble.remove(0);

				finalMove = pickMove(pick, checkType(pick));

			}
			else
			{
				ArrayList<Move> pick = vSingle.firstElement();
				vSingle.remove(0);

				finalMove = checkSingle(pick);
			}
		}

		nMoves++;
		System.out.println("Returning a move.");
		addMove(finalMove.Row(),finalMove.Col(),1);
		return finalMove;
	}

	public void gameOver(int outcome, Move lastOpponentMove){

		// THIS IS SOMETHING YOU MUST HAVE
		// WHEN THE OPPONENT CHOSES A MOVE, WINNING THE GAME
		if (lastOpponentMove!=null) 
			board[lastOpponentMove.Row()][lastOpponentMove.Col()]=2;

		if (outcome==1)
			System.out.println("YAHOOO !!! ... I won!");
		else if (outcome==2)
			System.out.println("Ooops!!!... I lost :(");
		else if (outcome==3)
			System.out.println("Whooyaa!!!... The other player gives up!");
		else if (outcome==4)
			System.out.println("Dang!!!... It's a Tie");
		// Printing the board...
		char p2;
		if (symbol=='x') p2='o';
		else p2='x';
		System.out.println("\nI am: "+symbol+"\n");
		System.out.println("Final Game State:\n");
		for (int i=0;i<32;i++) {
			for (int j=0;j<32;j++) {
				if (board[i][j]==0) System.out.print('.');
				else if (board[i][j]==1) System.out.print(symbol);
				else if (board[i][j]==2) System.out.print(p2);
				else System.out.print('?');

			}
			System.out.println("");
		}

		nMoves=0;
	}

	// **** THIS POINT AND BELOW IS FOR ADVANCED PROGRAMMERS

	// You make use of this method if you want to take advantage of the time
	// it requires for your opponent to respond. What you can do in this time
	// is upto you. But once the opponent responds with a move you must stop
	// what you are doing and start the Update_Game() method. You have 3 seconds
	// since then to respond.
	private void Waiting_For_Opponent(){

		// Your code below... Make sure to break your loop or anything youre
		// doing whenever isActive becomes false... Your thread enters the
		// idle state and waits until the isActive is true again...
		int dummy=0;
		while (true)
		{
			isRunning=true;
			while (isActive){
				// Do something useful here...
				dummy++;
				//System.out.println("Haha Doing Something..."+dummy);
				// remove the sleep statement below when you're actually 
				// doing something...
				Sleep(10);
			}
			isRunning=false;

			while(!isActive){
				Sleep(10);
			}

		}

	}




	// ***** DO NOT MODIFY THE CODE BELOW



	// The following are internal methods and you probably wouldn't need to 
	// change... unless you want to change the game processing logic.
	// PLEASE BE CAUTIOUS....
	public void Set_Active(boolean active){
		isActive=active;
		if (!isActive)
			while (isRunning) Sleep(10);
	}
	public void run(){
		Waiting_For_Opponent();
	}

	private void Sleep(int ms){
		try{
			sleep(ms);
		}
		catch(Exception e){
			// Do nothing...
		}
	}
	public Game(){
		isActive=false;
		isRunning=false;
		symbol='?';
		// Initialize your game here...
		App_Startup();
	}
	public void setSymbol(char sym){
		symbol=sym;
	}
	public String getUserName(){
		return myName;
	}
	public String getUserPassword(){
		return myPass;
	}


	public void checkLeftRight()
	{
		System.out.println("Checking left/right");
		for(int i = 0; i < 32; i++)
		{
			ArrayList<Move> temp = new ArrayList<Move>();
			for(int j = 0; j < 32; j++)
			{
				if((board[i][j] == 0)||(board[i][j] == 1)) //no move played at this spot
				{
					if(!temp.isEmpty()) //if we're not keeping track of anything yet
					{
						ArrayList<Move> temp2 = new ArrayList<Move>();
						temp2 = temp;
						vLeftToRight.add(temp2);
						temp = new ArrayList<Move>();
					}
				}
				else //if we find a series of moves
				{

					temp.add(new Move(i,j));
				}
			}
		}
	}

	public void checkUpDown()
	{
		System.out.println("Checking up/down");
		ArrayList<Move> temp = new ArrayList<Move>();

		for(int j = 0; j < 32; j++)
		{
			for(int i = 0; i < 32; i++)
			{
				if((board[i][j] == 0)||(board[i][j] == 1)) //no move played at this spot
				{
					if(!temp.isEmpty()) //if we're not keeping track of anything yet
					{
						vTopToBottom.add(temp);
						temp = new ArrayList<Move>();
					}
				}
				else //if we find a series of moves
				{
					temp.add(new Move(i,j));
				}
			}
		}
	}

	public void checkDiagonalRightLeft()
	{
		System.out.println("Checking diag right left");
		ArrayList<Move> temp = new ArrayList<Move>();
		//going "up"
		for(int diag = 0; diag < 32; diag++)
		{
			int i = diag;
			int j = 31;

			while(i > -1)
			{
				if((board[i][j] == 0)||(board[i][j] == 1)) //no move played at this spot
				{
					if(!temp.isEmpty()) //if we're not keeping track of anything yet
					{
						System.out.println("Writing temp to vector");
						vDiagonalRightToLeft.add(temp);
						temp = new ArrayList<Move>();
					}
				}
				else //if we find a series of moves
				{
					System.out.println("Adding move " +i +j + "to temp");
					temp.add(new Move(i,j));
				}
				i--;
				j--;
			}
		}

		temp.clear();
		//going "down"
		for(int diag = 30; diag > -1; diag--)
		{
			int i = 31;
			int j = diag;

			while(j > -1)
			{
				if((board[i][j] == 0)||(board[i][j] == 1)) //no move played at this spot
				{
					if(!temp.isEmpty())
					{//if we're not keeping track of anything yet
						vDiagonalRightToLeft.add(temp);
						temp = new ArrayList<Move>();
					}

				}
				else //if we find a series of moves
				{
					System.out.println("Adding move " +i +j + "to temp");
					temp.add(new Move(i,j));
				}
				i--;
				j--;
			}
		}
	}

	public void checkDiagonalLeftRight()
	{
		System.out.println("Checking diag left right");
		ArrayList<Move> temp = new ArrayList<Move>();
		//going "up"
		for(int diag = 0; diag < 32; diag++)
		{
			int i = diag;
			int j = 0;

			while(i > -1)
			{
				if((board[i][j] == 0)||(board[i][j] == 1)) //no move played at this spot
				{
					if(!temp.isEmpty()) //if we're not keeping track of anything yet
					{
						System.out.println("Adding to diagonal vector");
						vDiagonalLeftToRight.add(temp);
						temp = new ArrayList<Move>();
					}
				}
				else //if we find a series of moves
				{
					System.out.println("Printing square: " +board[i][j] +"at " +i+j);
					temp.add(new Move(i,j));
				}
				i--;
				j++;
			}
		}
		System.out.println("Entering left right going down part......");
		temp.clear();
		//going "down"
		for(int diag = 1; diag < 32; diag++)
		{
			System.out.println("Entering left right going down part");
			int i = 31;
			int j = diag;

			while(j < 32)
			{
				if((board[i][j] == 0)||(board[i][j] == 1)) //no move played at this spot
				{
					if(!temp.isEmpty()) //if we're not keeping track of anything yet
					{
						System.out.println("Adding to vDiagonalLeftToRight");
						vDiagonalLeftToRight.add(temp);
						temp = new ArrayList<Move>();
					}
				}
				else //if we find a series of moves
				{
					System.out.println("Adding move " +i +j + "to temp");
					temp.add(new Move(i,j));
				}
				i--;
				j++;
			}
		}
	}

	public void createtestBoard()
	{
		board[1][4] = 2;
		board[2][2] = 2;
		board[2][3] = 2;
		board[2][4] = 2;
		board[3][4] = 2;
	}

	public ArrayList getInsideLeftRight(int spot)
	{
		return (ArrayList) vLeftToRight.get(spot);
	}

	public void grabSingles()
	{
		System.out.println("Grabbing singles");
		for(int i = 0; i < vTopToBottom.size(); i++)
		{
			if(vTopToBottom.get(i).size() == 1)
				vSingle.add(vTopToBottom.get(i));    
		}

		for(int i = 0; i < vLeftToRight.size(); i++)
		{
			if(vLeftToRight.get(i).size() == 1)
				vSingle.add(vLeftToRight.get(i));    
		}

		for(int i = 0; i < vDiagonalLeftToRight.size(); i++)
		{
			if(vDiagonalLeftToRight.get(i).size() == 1)
				vSingle.add(vDiagonalLeftToRight.get(i));    
		}

		for(int i = 0; i < vDiagonalRightToLeft.size(); i++)
		{
			if(vDiagonalRightToLeft.get(i).size() == 1)
				vSingle.add(vDiagonalRightToLeft.get(i));
		}
	}

	public void grabDoubles()
	{
		System.out.println("Grabbing doubles");
		for(int i = 0; i < vTopToBottom.size(); i++)
		{
			if(vTopToBottom.get(i).size() == 2)
				vDouble.add(vTopToBottom.get(i));
		}

		for(int i = 0; i < vLeftToRight.size(); i++)
		{
			if(vLeftToRight.get(i).size() == 2)
				vDouble.add(vLeftToRight.get(i));
		}

		for(int i = 0; i < vDiagonalLeftToRight.size(); i++)
		{
			if(vDiagonalLeftToRight.get(i).size() == 2)
				vDouble.add(vDiagonalLeftToRight.get(i));
		}

		for(int i = 0; i < vDiagonalRightToLeft.size(); i++)
		{
			if(vDiagonalRightToLeft.get(i).size() == 2)
				vDouble.add(vDiagonalRightToLeft.get(i));
		}
	}

	public void grabTriples()
	{
		System.out.println("Grabbing triples");
		for(int i = 0; i < vTopToBottom.size(); i++)
		{
			if(vTopToBottom.get(i).size() == 3)
				vTriple.add(vTopToBottom.get(i));
		}

		for(int i = 0; i < vLeftToRight.size(); i++)
		{
			if(vLeftToRight.get(i).size() == 3)
				vTriple.add(vLeftToRight.get(i));
		}

		for(int i = 0; i < vDiagonalLeftToRight.size(); i++)
		{
			if(vDiagonalLeftToRight.get(i).size() == 3)
				vTriple.add(vDiagonalLeftToRight.get(i));
		}

		for(int i = 0; i < vDiagonalRightToLeft.size(); i++)
		{
			if(vDiagonalRightToLeft.get(i).size() == 3)
				vTriple.add(vDiagonalRightToLeft.get(i));
		}
	}

	public void grabQuads()
	{
		System.out.println("Grabbing quads");
		for(int i = 0; i < vTopToBottom.size(); i++)
		{
			if(vTopToBottom.get(i).size() == 4)
				vQuad.add(vTopToBottom.get(i));
		}

		for(int i = 0; i < vLeftToRight.size(); i++)
		{
			if(vLeftToRight.get(i).size() == 4)
				vQuad.add(vLeftToRight.get(i));
		}

		for(int i = 0; i < vDiagonalLeftToRight.size(); i++)
		{
			if(vDiagonalLeftToRight.get(i).size() == 4)
				vQuad.add(vDiagonalLeftToRight.get(i));
		}

		for(int i = 0; i < vDiagonalRightToLeft.size(); i++)
		{
			if(vDiagonalRightToLeft.get(i).size() == 4)
				vQuad.add(vDiagonalRightToLeft.get(i));
		}
	}


	public int checkType(ArrayList<Move> theList)
	{
		Move first = theList.get(0);
		Move second = theList.get(1);

		if(first.Row() < second.Row())
		{
			if(first.Col() > second.Col())
			{
				return 3; // right to left diag
			}
			else if(first.Col() < second.Col())
			{
				return 4; //left to right diag
			}
			else
			{
				return 2; //top to bottom
			}


		}
		else if(first.Row() > second.Row())
		{
			if(first.Col() > second.Col())
			{
				return 4; //left to right diag
			}
			else if(first.Col() < second.Col())
			{
				return 3; //right to left diag
			}
			else
			{
				return 2; //top to bottom
			}
		}
		else
		{
			return 1; //left to right
		}

	}


	public Move pickMove(ArrayList<Move> theList, int theType)
	{
		System.out.println("Picking move...");
		Move L = theList.get(0);
		Move R = theList.get(theList.size() - 1);
		System.out.println("Move L: row and col are: " +L.Row() + L.Col());
		System.out.println("Move R: row and col are: " +R.Row() + R.Col());
		Move Lnext;
		Move Rnext;


		if(theType == 1) //left to right
		{
			Lnext = new Move(L.Row(),L.Col()-1);
			Rnext = new Move(R.Row(),R.Col()+1);

			if(Lnext.isBound() && Rnext.isBound())
			{
				Random generator = new Random();
				System.out.println("Generating random number");
				int num = Math.abs(generator.nextInt() % 2);
				System.out.println("Number generated");
                System.out.println("Generating random number - got here");
				if(num == 0)
					return isFree(Lnext);
				else
					return isFree(Rnext);
			}
			else if(Lnext.isBound() && !Rnext.isBound())
			{
				return isFree(Lnext);
			}
			else if(!Lnext.isBound() && Rnext.isBound())
			{
				return isFree(Rnext);
			}
			else
			{
				return null;
			}
		}
		else if(theType == 2) //top to bottom
		{
			System.out.println("Top to bottom clause");
			Lnext = new Move(L.Row()-1,L.Col());
			Rnext = new Move(R.Row()+1,R.Col());
			System.out.println("Move Lnext: row and col are: " +Lnext.Row() + Lnext.Col());
			System.out.println("Move Rnext: row and col are: " +Rnext.Row() + Rnext.Col());
			if(Lnext.isBound() && Rnext.isBound())
			{
				System.out.println("Both bound");
				Random generator = new Random();
				int num = Math.abs(generator.nextInt() % 2);
				System.out.println("Found num is: " + num);
				if(num == 0)
					return isFree(Lnext);
				else
					return isFree(Rnext);
			}
			else if(Lnext.isBound() && !Rnext.isBound())
			{
				System.out.println("Left bound");
				return isFree(Lnext);
			}
			else if(!Lnext.isBound() && Rnext.isBound())
			{
				System.out.println("Right bound");
				return isFree(Rnext);
			}
			else
			{
				System.out.println("Neither bound. Both null");
				return null;
			}
		}
		else if(theType == 3) //left to right diag
		{
			System.out.println("Diag left to right");
			Lnext = new Move(L.Row()+1,L.Col() - 1);
			Rnext = new Move(R.Row()-1,R.Col() + 1);
			System.out.println("Move Lnext: row and col are: " +Lnext.Row() + Lnext.Col());
			System.out.println("Move Rnext: row and col are: " +Rnext.Row() + Rnext.Col());
			
			if(Lnext.isBound() && Rnext.isBound())
			{
				Random generator = new Random();
				int num = Math.abs(generator.nextInt() % 2);

				if(num == 0)
					return isFree(Lnext);
				else
					return isFree(Rnext);
			}
			else if(Lnext.isBound() && !Rnext.isBound())
			{
				return isFree(Lnext);
			}
			else if(!Lnext.isBound() && Rnext.isBound())
			{
				return isFree(Rnext);
			}
			else
			{
				return null;
			}


		}
		else //right to left diag
		{
			System.out.println("Diag right to left");
			Lnext = new Move(L.Row()+1,L.Col()+ 1);
			Rnext = new Move(R.Row() - 1,R.Col() - 1);
			System.out.println("Move Lnext: row and col are: " +Lnext.Row() + Lnext.Col());
			System.out.println("Move Rnext: row and col are: " +Rnext.Row() + Rnext.Col());
			
			if(Lnext.isBound() && Rnext.isBound())
			{
				System.out.println("isbound of diag right left");
				Random generator = new Random();
				int num = Math.abs(generator.nextInt() % 2);

				if(num == 0)
					return isFree(Lnext);
				else
					return isFree(Rnext);
			}
			else if(Lnext.isBound() && !Rnext.isBound())
			{
				return isFree(Lnext);
			}
			else if(!Lnext.isBound() && Rnext.isBound())
			{
				return isFree(Rnext);
			}
			else
			{
				return null;
			}

		}
	}

	public Move checkSingle(ArrayList<Move> theList)
	{
		System.out.println("Checking singles");
		Move original = theList.get(0);
		Move L = new Move(original.Row(), original.Col() - 1);
		Move R = new Move(original.Row(), original.Col() + 1);
		Move T = new Move(original.Row() - 1, original.Col());
		Move B = new Move(original.Row() + 1, original.Col());
		Move uL = new Move(original.Row() - 1, original.Col() - 1);
		Move bL = new Move(original.Row() + 1, original.Col() - 1);
		Move uR = new Move(original.Row() - 1, original.Col() + 1);
		Move bR = new Move(original.Row() + 1, original.Col() + 1);

		ArrayList<Move> moveSet = new ArrayList<Move>();
        moveSet.add(uL);
        moveSet.add(bL);
        moveSet.add(uR);
        moveSet.add(bR);
        moveSet.add(T);
        moveSet.add(B);
        moveSet.add(L);
        moveSet.add(R);

		Move theMove = null;

        int i = 0;
		while(i < 10)
		{
			Random generator = new Random();
			int num = Math.abs(generator.nextInt() % moveSet.size());
			System.out.println("Num value is " + num);
			if(moveSet.get(num).isBound())
			{
				
				theMove = isFree(moveSet.get(num));
                if(theMove != null)
                    i = 100;
                else
                    i++;
			}
			else
				i++;
		}

        System.out.println("Checking singles - Done!");

		return theMove;

	}


	public Move isFree(Move theMove)
	{
		if(board[theMove.Row()][theMove.Col()] == 1)
			return null; //we've already gone there
		else
			return theMove; //we can go there
	}

	public void addMove(int row, int col, int move)
	{
		board[row][col] = move;
	}

}

